Dart eval:Compiler populateLookupTablesForDeclaration
介绍
解析 Library 中的所有声明,并更新到 Context 注册表中。
方法签名:
void _populateLookupTablesForDeclaration(
int libraryIndex,
DeclarationOrBridge declarationOrBridge) {
入参:
- 库的索引
- 对应的声明,具体指 Top level declaration
初始化工作:
void _populateLookupTablesForDeclaration(
int libraryIndex, DeclarationOrBridge declarationOrBridge) {
// 如果没有初始化,则初始化
if (!_topLevelDeclarationsMap.containsKey(libraryIndex)) {
_topLevelDeclarationsMap[libraryIndex] = {};
}
// 如果没有初始化,则初始化
if (!_instanceDeclarationsMap.containsKey(libraryIndex)) {
_instanceDeclarationsMap[libraryIndex] = {};
}
// ……
根据 declarationOrBridge 的类型,解析分为几种类型:
- 是不是 Bridge:桥接类
- 是不是 TopLevelVariableDeclaration:顶层变量声明
- NamedCompilationUnitMember:顶层其它声明,如类声明
Bridge 处理逻辑
如果是 Bridge:
// 如果是 Bridge
if (declarationOrBridge.isBridge) {
// 获取到这个 Bridge
final bridge = declarationOrBridge.bridge!;
// 还区分 Bridge 桥接的类型
// 1. 桥接类
// 2. 桥接枚举
// 3. 桥接方法
// 如果是类桥接
if (bridge is BridgeClassDef) {
final spec = bridge.type.type.spec!;
// 类本身放进去
_topLevelDeclarationsMap[libraryIndex]![spec.name] =
DeclarationOrBridge(libraryIndex, bridge: bridge);
// 一个类可能有多个构造方法,放进去
for (final constructor in bridge.constructors.entries) {
_topLevelDeclarationsMap[libraryIndex]![
'${spec.name}.${constructor.key}'] =
DeclarationOrBridge(libraryIndex, bridge: constructor.value);
}
// 一个类可能有多个方法,放进去
for (final method in bridge.methods.entries) {
if (method.value.isStatic) {
_topLevelDeclarationsMap[libraryIndex]![
'${spec.name}.${method.key}'] =
DeclarationOrBridge(libraryIndex, bridge: method.value);
}
}
} else if (bridge is BridgeEnumDef) { // 枚举桥接
final spec = bridge.type.spec!;
_topLevelDeclarationsMap[libraryIndex]![spec.name] =
DeclarationOrBridge(libraryIndex, bridge: bridge);
} else if (bridge is BridgeFunctionDeclaration) { // 方法桥接
_topLevelDeclarationsMap[libraryIndex]![bridge.name] =
DeclarationOrBridge(libraryIndex, bridge: bridge);
}
return;
}
从中可以看出,哪一种桥接声明,就创建一个 DeclarationOrBridge,如果是桥接类,创建的声明更多一些。
类桥接处理
向顶层声明注册表中注册:
- 桥接类名称
- 构造方法(可能不止一个):桥接类名.构造方法名
- 方法(不止一个):桥接类名.方法名
注册内容都是:DeclarationOrBridge,是对 Dart Analyzer AST 不同粒度的拆分,这样就把 AST,从大的类粒度,拆得更细了。
// 如果是类桥接
if (bridge is BridgeClassDef) {
final spec = bridge.type.type.spec!;
// 类本身放进去
// Map 第一个维度:library 对应的标识
// Map 第二个维度:桥接类的名称
_topLevelDeclarationsMap[libraryIndex]![spec.name] =
DeclarationOrBridge(libraryIndex, bridge: bridge);
// 对于类桥接,不仅要将类名注册到顶层声明,还要注册:
// 1. 构造方法(可能不止一个):桥接类名.构造方法名
// 2. 方法(不止一个):桥接类名.方法名
// 一个类可能有多个构造方法,放进去
for (final constructor in bridge.constructors.entries) {
_topLevelDeclarationsMap[libraryIndex]![
'${spec.name}.${constructor.key}'] =
DeclarationOrBridge(libraryIndex, bridge: constructor.value);
}
// 一个类可能有多个方法,放进去
for (final method in bridge.methods.entries) {
if (method.value.isStatic) {
_topLevelDeclarationsMap[libraryIndex]![
'${spec.name}.${method.key}'] =
DeclarationOrBridge(libraryIndex, bridge: method.value);
}
}
}
TopLevelVariableDeclaration 处理逻辑
顶层变量声明处理逻辑。注:TopLevelVariableDeclaration 参见《Dart Analyzer:TopLevelVariableDeclaration》
变量声明可以一次声明多个变量,首先获取这些变量:
final vlist = declaration.variables;
这里初始化了 3 个结构,说明这些结构要用到:
if (!_topLevelGlobalIndices.containsKey(libraryIndex)) {
_topLevelGlobalIndices[libraryIndex] = {};
ctx.topLevelGlobalInitializers[libraryIndex] = {};
ctx.topLevelVariableInferredTypes[libraryIndex] = {};
}
遍历这些变量进行处理:
for (final variable in vlist.variables) {
// 变量名
final name = variable.name2.value() as String;
// 如果重复定义全局变量,会抛出异常
if (_topLevelDeclarationsMap[libraryIndex]!.containsKey(name)) {
throw CompileError('Cannot define "$name" twice in the same library',
variable, libraryIndex);
}
// 向顶层声明注册表中注册该顶层变量
_topLevelDeclarationsMap[libraryIndex]![name] =
DeclarationOrBridge(libraryIndex, declaration: variable);
// _topLevelGlobalIndices 是维护全局标识的,看起来顶层每个东西都有一个唯一标识
// 自增
_topLevelGlobalIndices[libraryIndex]![name] = ctx.globalIndex++;
}